package com.ocean.weixin.utils;

/**
 * @auther DLY
 * @create 2017/9/18
 */

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;

public class HttpUtils {
    private static final int TIMEOUT = 20000;// 10秒

    protected static HttpURLConnection createHttpConnection(URI uri) throws Exception {
        URLConnection urlConnection = uri.toURL().openConnection();
        if (uri.getScheme().equals("https")) {
            try {
                SSLContext sslContext = null;
                HostnameVerifier hostnameVerifier = null;
                if (sslContext == null) {
                    sslContext = allowSSLContext();
                }
                if (hostnameVerifier == null) {
                    hostnameVerifier = createHostnameVerifier();
                }
                HttpsURLConnection connection = (HttpsURLConnection) urlConnection;
                connection.setSSLSocketFactory(sslContext.getSocketFactory());
                connection.setHostnameVerifier(hostnameVerifier);
                return connection;
            } catch (Exception e) {
                throw new Exception(e);
            }
        } else {
            return (HttpURLConnection) urlConnection;
        }
    }

    protected static HostnameVerifier createHostnameVerifier() {
        return new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
    }

    public static SSLContext allowSSLContext() throws Exception {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null,
                new X509TrustManager[] { createX509TrustManager() },
                new java.security.SecureRandom());
            return sslContext;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("Create SSLContext NoSuchAlgorithmException:", e);
        } catch (KeyManagementException e) {
            throw new Exception("Create SSLContext KeyManagementException:", e);
        }
    }

    protected static X509TrustManager createX509TrustManager() {
        return new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkServerTrusted(
                X509Certificate[] paramArrayOfX509Certificate,
                String paramString) throws CertificateException {
            }

            @Override
            public void checkClientTrusted(
                X509Certificate[] paramArrayOfX509Certificate,
                String paramString) throws CertificateException {
            }
        };
    }

    protected static InputStream getInputStream(HttpURLConnection conn) throws Exception {
        if(conn == null)
            return null;

//      showHeader(conn);

        String contentEncoding = conn.getHeaderField("Content-Encoding");
        if(contentEncoding != null && contentEncoding.contains("gzip")) {
            return new GZIPInputStream(conn.getInputStream());
        } else {
            return conn.getInputStream();
        }

    }

    /**
     * 传送文本,例如Json,xml等
     */
    public static String sendText(String urlPath, String txt) throws Exception {
        return sendText(urlPath, txt, "UTF-8", null);
    }

    public static String sendText(String urlPath, String txt, Map<String, String> headers) throws Exception {
        return sendText(urlPath, txt, "UTF-8", headers);
    }

    public static String sendText(String urlPath, String txt, String encoding) throws Exception {
        return sendText(urlPath, txt, encoding, null);
    }

    public static String sendText(String urlPath, String txt, String encoding, Map<String, String> headers) throws Exception {
        byte[] sendData = txt.getBytes();
        HttpURLConnection conn = createHttpConnection(URI.create(urlPath));
        conn.setRequestMethod("POST");
        conn.setConnectTimeout(TIMEOUT);
        conn.setReadTimeout(TIMEOUT);
        // 如果通过post提交数据，必须设置允许对外输出数据
        conn.setDoOutput(true);

        if(headers != null) {
            Set<Map.Entry<String, String>> set = headers.entrySet();
            for(Map.Entry<String, String> entry : set) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        conn.setRequestProperty("Accept-Encoding", "gzip,deflate");
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        conn.setRequestProperty("Charset", encoding);
        conn.setRequestProperty("Content-Length", String.valueOf(sendData.length));
        OutputStream outStream = conn.getOutputStream();
        outStream.write(sendData);
        outStream.flush();
        outStream.close();
        if (conn.getResponseCode() == 200) {

            // 获得服务器响应的数据
//          String responseData = "";
//          byte[] b = IOUtils.toByteArray(new GZIPInputStream(conn.getInputStream()));

            /*
            System.out.println("长度========================" + b.length);
            responseData = new String(b);*/

            BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream(conn), encoding));
            // 数据
            String retData = null;
            String responseData = "";
            while ((retData = in.readLine()) != null) {
                responseData += retData;
            }
            in.close();
            return responseData;
        } else {
            printErrorMessage(conn);
        }
        return "sendText error!";
    }

    /**
     * 上传文件
     */
    public static String sendFile(String urlPath, String filePath) throws Exception {
        return sendFile(urlPath, filePath, null, null);
    }
    public static String sendFile(String urlPath, String filePath, Map<String, String> headers) throws Exception {
        return sendFile(urlPath, filePath, null, headers);
    }
    public static String sendFile(String urlPath, String filePath, String newName) throws Exception {
        return sendFile(urlPath, filePath, newName, null);
    }
    public static String sendFile(String urlPath, String filePath, String newName, Map<String, String> headers) throws Exception {
        String end = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";

        File file = new File(filePath);
        HttpURLConnection con = createHttpConnection(URI.create(urlPath));
        /* 允许Input、Output，不使用Cache */
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        /* 设置传送的method=POST */
        con.setRequestMethod("POST");
        /* setRequestProperty */

        if(headers != null) {
            Set<Map.Entry<String, String>> set = headers.entrySet();
            for(Map.Entry<String, String> entry : set) {
                con.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");
        con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

        /* 设置DataOutputStream */
        DataOutputStream ds = new DataOutputStream(con.getOutputStream());
        ds.writeBytes(twoHyphens + boundary + end);
        ds.writeBytes("Content-Disposition: form-data; " + "name=\"file1\";filename=\"" + (newName == null ? file.getName() : newName) + "\"" + end);
        ds.writeBytes(end);

        /* 取得文件的FileInputStream */
        FileInputStream fStream = new FileInputStream(file);
        /* 设置每次写入1024bytes */
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];

        int length = -1;
        /* 从文件读取数据至缓冲区 */
        while ((length = fStream.read(buffer)) != -1) {
            /* 将资料写入DataOutputStream中 */
            ds.write(buffer, 0, length);
        }
        ds.writeBytes(end);
        ds.writeBytes(twoHyphens + boundary + twoHyphens + end);

        /* close streams */
        fStream.close();
        ds.flush();

        if (con.getResponseCode() == 200) {
        /* 取得Response内容 */
            InputStream is = getInputStream(con);
            StringBuffer b = new StringBuffer();
            InputStreamReader inputStreamReader = new InputStreamReader(is, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                b.append(str);
            }
        /*StringBuffer b = new StringBuffer();
        while ((ch = is.read()) != -1) {
            b.append((char) ch);
        }*/
        /* 关闭DataOutputStream */
            ds.close();
            return b.toString();
        } else {
            printErrorMessage(con);
            return null;
        }
    }

    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
        return httpsRequest(requestUrl, requestMethod, outputStr);
    }

    /**
     * 发起https请求并获取结果
     *
     * @param requestUrl
     *            请求地址
     * @param requestMethod
     *            请求方式（GET、POST）
     * @param outputStr
     *            提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        String respStr = null;
        StringBuffer buffer = new StringBuffer();
        try {
            HttpURLConnection httpUrlConn = createHttpConnection(URI.create(requestUrl));

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);
            httpUrlConn.setRequestProperty("Content-Type", "text/plain;charset=UTF-8");


            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式，防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = getInputStream(httpUrlConn);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            respStr = buffer.toString();

            // jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            System.out.println("server connection timed out.");
        } catch (Exception e) {
            System.out.println("https request error:{}" + e.getMessage());
            e.printStackTrace();
        }
        return respStr;
    }

    /**
     * 通过get方式提交参数给服务器
     */
    public static String sendGetRequest(String urlPath, Map<String, String> params) throws Exception {
        return sendGetRequest(urlPath, params, "UTF-8", null);
    }
    public static String sendGetRequest(String urlPath, Map<String, String> params, Map<String, String> headers) throws Exception {
        return sendGetRequest(urlPath, params, "UTF-8", headers);
    }
    public static String sendGetRequest(String urlPath, Map<String, String> params, String encoding) throws Exception {
        return sendGetRequest(urlPath, params, encoding, null);
    }
    public static String sendGetRequest(String urlPath, Map<String, String> params, String encoding, Map<String, String> headers) throws Exception {

        // 使用StringBuilder对象
        StringBuilder sb = new StringBuilder(urlPath);
        if (params != null) {
            sb.append('?');
            // 迭代Map
            for (Map.Entry<String, String> entry : params.entrySet()) {
                sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), encoding)).append('&');
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        // 打开链接
        HttpURLConnection conn = createHttpConnection(URI.create(sb.toString()));
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-Type", "text/xml");
        conn.setRequestProperty("Charset", encoding);
        conn.setRequestProperty("Accept-Encoding", "gzip,deflate");
        conn.setConnectTimeout(TIMEOUT);
        conn.setReadTimeout(TIMEOUT);
        if(headers != null) {
            Set<Map.Entry<String, String>> set = headers.entrySet();
            for(Map.Entry<String, String> entry : set) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }

        // 如果请求响应码是200，则表示成功
        if (conn.getResponseCode() == 200) {
            // 获得服务器响应的数据
            BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream(conn), encoding));
            // 数据
            String retData = null;
            String responseData = "";
            while ((retData = in.readLine()) != null) {
                responseData += retData;
            }
            in.close();
            return responseData;
        } else {
            printErrorMessage(conn);
        }
        return "sendGetRequest error!";

    }

    /**
     * 通过Post方式提交参数给服务器,也可以用来传送json或xml文件
     */
    public static String sendPostRequest(String urlPath, Map<String, String> params, String encoding) throws Exception {
        StringBuilder sb = new StringBuilder();
        // 如果参数不为空
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                // Post方式提交参数的话，不能省略内容类型与长度
                sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), encoding)).append('&');
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        // 得到实体的二进制数据
        byte[] entitydata = sb.toString().getBytes();
        HttpURLConnection conn = createHttpConnection(URI.create(urlPath));
        conn.setRequestMethod("POST");
        conn.setConnectTimeout(TIMEOUT);
        conn.setReadTimeout(TIMEOUT);
        // 如果通过post提交数据，必须设置允许对外输出数据
        conn.setDoOutput(true);
        // 这里只设置内容类型与内容长度的头字段
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        // conn.setRequestProperty("Content-Type", "text/xml");
        conn.setRequestProperty("Charset", encoding);
        conn.setRequestProperty("Content-Length", String.valueOf(entitydata.length));
        OutputStream outStream = conn.getOutputStream();
        // 把实体数据写入是输出流
        outStream.write(entitydata);
        // 内存中的数据刷入
        outStream.flush();
        outStream.close();
        // 如果请求响应码是200，则表示成功
        if (conn.getResponseCode() == 200) {
            // 获得服务器响应的数据
            BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream(conn), encoding));
            // 数据
            String retData = null;
            String responseData = "";
            while ((retData = in.readLine()) != null) {
                responseData += retData;
            }
            in.close();
            return responseData;
        } else {
            printErrorMessage(conn);
        }
        return "sendText error!";
    }
    /**
     * 根据URL直接读文件内容，前提是这个文件当中的内容是文本，函数的返回值就是文件当中的内容
     */
    public static String readTxtFile(String urlStr, String encoding) throws Exception {
        StringBuffer sb = new StringBuffer();
        String line = null;
        BufferedReader buffer = null;
        try {
            // 创建一个URL对象
            // 创建一个Http连接
            HttpURLConnection urlConn = createHttpConnection(URI.create(urlStr));
            // 使用IO流读取数据
            buffer = new BufferedReader(new InputStreamReader(getInputStream(urlConn), encoding));
            while ((line = buffer.readLine()) != null) {
                sb.append(line);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                buffer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

    /**
     * 该函数返回整形 -1：代表下载文件出错 0：代表下载文件成功 1：代表文件已经存在
     */
    public static int downloadFile(String urlStr, String path, String fileName) throws Exception {
        InputStream inputStream = null;
        try {
            inputStream = getInputStreamFromUrl(urlStr);
            File resultFile = write2FileFromInput(path, fileName, inputStream);
            if (resultFile == null) {
                return -1;
            }

        } catch (Exception e) {
            return -1;
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                throw e;
            }
        }
        return 0;
    }

    /**
     * 根据URL得到输入流
     *
     * @param urlStr
     * @return
     * @throws MalformedURLException
     * @throws IOException
     */
    public static InputStream getInputStreamFromUrl(String urlStr) throws MalformedURLException, IOException {
        HttpURLConnection urlConn = null;
        try {
            urlConn = createHttpConnection(URI.create(urlStr));
        } catch (Exception e) {
            e.printStackTrace();
        }
        InputStream inputStream = urlConn.getInputStream();
        return inputStream;
    }

    /**
     * 将一个InputStream里面的数据写入到SD卡中
     */
    private static File write2FileFromInput(String directory, String fileName, InputStream input) {
        File file = null;
        String tmpPath = System.getProperty("java.io.tmpdir");
        FileOutputStream output = null;
        File dir = new File(tmpPath + directory);
        if (!dir.exists()) {
            dir.mkdir();
        }
        try {
            file = new File(dir + File.separator + fileName);
            file.createNewFile();
            output = new FileOutputStream(file);
            byte buffer[] = new byte[1024];
            while ((input.read(buffer)) != -1) {
                output.write(buffer);
            }
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }

    public static void printErrorMessage(HttpURLConnection conn) throws Exception {
        showHeader(conn);
        /*List<String> server = map.get("Server");

        if (server == null) {
            System.out.println("Key 'Server' is not found!");
        } else {
            for (String values : server) {
                System.out.println(values);
            }
        }*/
        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
        // 数据
        String retData = null;
        String responseData = "";
        while ((retData = in.readLine()) != null) {
            responseData += retData;
        }
        in.close();

        System.out.println(responseData);
    }

    public static void showHeader(HttpURLConnection conn) {
        Map<String, List<String>> map = conn.getHeaderFields();

        System.out.println("显示响应Header信息");

        for (Map.Entry<String, List<String>> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "  : " + entry.getValue());
        }

        System.out.println("使用key获得响应Header信息");
    }


}